package com.shihb.chapter03oop

/**
 * 动态混入,叠加特质
 */
object Demo10MixIn {
  def main(args: Array[String]): Unit = {
    test3
  }
  //1、动态混入
  def test: Unit ={
    // 在不修改类的定义基础，让他们使用trait方法
    val oracleDb = new OracleDb with Operate
    oracleDb.insert(1)
    val mysqlDb = new MysqlDb with Operate
    mysqlDb.insert(200)
    // 如有抽象类有抽象方法实现要写在动态混入后面
    val kuduDb = new KuduDb with Operate {
      override def say: Unit = println("kudu")
    }
    kuduDb.insert(300)
    kuduDb.say
  }
  //2、叠加特质,动态混入多个
  def test2: Unit ={
    //创建实例时动态混入OperateSonFile，OperateSonDB

    //问题一:当创建动态混入对象时，顺序是怎么样的
    /**创建的顺序结果如下
     *
     * OracleDb... 1、调用当前类的自身
     * 2、再开始动态混入(从左往右)
     * 第一个特质(父->子)
     * 第二个特质(父->子)
     *    OperateFather...
     *    Operate...
     *    OperateSonDb...
     *    OperateSonFile...
     * 总结一句话：叠加特质声明时,从左往右执行
     */
    val db = new OracleDb with OperateSonDb with OperateSonFile
    //问题二：执行动态混入对象的方法时，顺序是怎么样的
    /**执行方法结果如下:
     *    向文件	向数据库		插入数据=100
     * 总结：
     *  1)叠加特质方法执行时,从右往左执行，
     *  2)当执行到super时，指向左边的特质
     *  3)如果没有则找父类
     */
    db.insert(100)
  }
  //3、声明时混入(静态混入)
  def test3: Unit ={
    //问题1：声明顺序
    /**
     * 把extends后当作一个整体
     * OracleDb...  1、调用当前类的超类
     * 2、调用特质(从左往右)
     * 第一个特质(父->子)
     * 第二个特质(父->子)
     * ...
     *   OperateFather...
     *   Operate...
     *   OperateSonDb...
     *   OperateSonFile...
     * HdfsDb...  3、调用当前类的自身
     */
    val db = new HdfsDb
    println("OK")
  }
}

trait OperateFather{
  println("OperateFather...")
  def insert(id: Int)
}

/**
 * 问题三：super值像抽象方法
 * 如果子特使重写/实现父特质方法调用的super
 * 这时方法不是完全实现,需要声明 abstract override否则报错
 * 这时super.insert(id)的调用和动态混入顺序有关，不一定调用父类的方法
 */
trait Operate2 extends  OperateFather {
  println("Operate2...")
  //需要声明 abstract override,否则报错
  abstract override def insert(id:Int): Unit ={
    println("我没有完全实现")
    //调用的super的insert时抽象方法
    super.insert(id)
  }
}

// 继承特质
trait Operate extends  OperateFather {
  println("Operate...")
  def insert(id:Int): Unit ={//实现了方法
    println("\t插入数据="+id)
  }
}

trait OperateSonDb extends Operate{
  println("OperateSonDb...")

  override def insert(id: Int): Unit = { //重写方法
    print("向数据库\t")
    super.insert(id)
  }
}
trait OperateSonFile extends Operate{
  println("OperateSonFile...")

  override def insert(id: Int): Unit = { //重写方法
    print("向文件\t")
    //调用了insert方法(难点),这里super在动态混入时不一定是父类
    //super.insert(id)
    //如果我们希望调用父特质的方法加泛型,只能是直接父特质
    super[Operate].insert(id)
  }
}
class HdfsDb extends OracleDb with OperateSonDb with OperateSonFile {
  println("HdfsDb...")
}

class OracleDb{
  println("OracleDb...")
}
abstract  class MysqlDb{

}
abstract  class KuduDb{
  def say
}
